// FIXME WA 0/1
`ifndef __HAMMING_ENCODER__
`define __HAMMING_ENCODER__

module hamming_encoder (
           input clk,
           input clk2,
           input rst_n,
           input din,
           input din_valid,
           output dout,
           output dout_valid);

reg dout_reg;
reg dout_valid_reg;
reg [1: 0] input_cnt;
reg [3: 0] input_buffer;
reg [2: 0] output_rest;
reg [7: 0] output_buffer;
reg output_enable;

assign dout_valid = dout_valid_reg;
assign dout = (dout_valid_reg == 1) ? dout_reg : 1'bX;

always @(posedge clk2 or negedge rst_n) begin // 不要使用多个触发规则，除非它们之间相互隔离
    if (rst_n == 0) begin
        dout_reg <= 0;
        dout_valid_reg <= 0;
        input_buffer <= 0;
        input_cnt <= 0;
        output_buffer <= 0;
        output_rest <= 0;
        output_enable <= 0;
    end
    else begin
        if (clk == 1) begin // 如果是clk时钟周期，还要单独执行以下clk的任务
            if (din_valid == 1) begin
                input_buffer[3 - input_cnt] <= din; // 往缓存中存入数据
                if (input_cnt == 3) begin
                    input_cnt <= 0; // 这个0在下一个周期才能被读取到！
                    output_enable <= 1; // 通知在下一个clk2上升沿，clk下降沿可以开始输出数据
                end
                else begin
                    input_cnt <= input_cnt + 1'b1; // 这个数据也只有在下一个周期才能被读取到！
                end
            end
            else begin
                output_enable <= 0;
            end
        end
        if (output_rest == 0) begin
            // 表明输出已经为空，开始请求输入
            if (output_enable == 1) begin
                // output_enable <= 0; // 清空使能数据
                output_buffer[0] <= input_buffer[0] ^ input_buffer[1] ^ input_buffer[3];
                output_buffer[1] <= input_buffer[0] ^ input_buffer[2] ^ input_buffer[3];
                output_buffer[2] <= input_buffer[0];
                output_buffer[3] <= input_buffer[1] ^ input_buffer[2] ^ input_buffer[3];
                output_buffer[4] <= input_buffer[1];
                output_buffer[5] <= input_buffer[2];
                output_buffer[6] <= input_buffer[3];
                output_buffer[7] <=
                             (input_buffer[0] ^ input_buffer[1] ^ input_buffer[3]) ^
                             (input_buffer[0] ^ input_buffer[2] ^ input_buffer[3]) ^
                             (input_buffer[1] ^ input_buffer[2] ^ input_buffer[3]) ^
                             input_buffer[0] ^ input_buffer[1] ^ input_buffer[2] ^ input_buffer[3];
                dout_reg <= input_buffer[0] ^ input_buffer[1] ^ input_buffer[3];
                output_rest <= 7;
                dout_valid_reg <= 1;
            end
            else begin
                // 没有使能可以输出，数据终止
                dout_valid_reg <= 0;
            end
        end
        else begin
            // 表明还有数据没有传输完成
            dout_reg <= output_buffer[8 - output_rest];
            output_rest <= output_rest - 1'b1;
        end
    end

    end

    endmodule

`endif